package com.linkgie.galaxyframework.security.ca;

import java.util.function.Supplier;

import com.linkgie.galaxyframework.crypto.CryptoKeypair;
import com.linkgie.galaxyframework.crypto.PrivateKey;
import com.linkgie.galaxyframework.crypto.PublicKey;

/**
 * 证书服务；
 * <p>
 * 定义了一套抽象的证书链实现提供者接口，目的是提供更简单的接口创建自定义证书链或操作标准证书链基础设施(x.509)；
 */
public interface CertificateService {

    /**
     * 算法；
     * 
     * @return
     */
    String getAlgorithm();

    /**
     * 创建一个根 CA 实例；
     * 
     * @param principal            主体；
     * @param key                  密钥对；
     * @param maxProgationDistance 根证书的最大传播距离；有效值要大于等于 0 ；
     *                             <p>
     *                             通过传播距离，可以控制证书链的延伸层级；
     *                             <p>
     *                             从根证书开始，每向下签发一级证书，新证书的最大传播距离至少减少 1 ，直至 0 ；
     *                             <p>
     *                             如果将根证书的最大传播距离设置为 0
     *                             时，意味着创建的根证书无法签发任何下级证书，根证书仅以自签名的方式自我认证；
     * @param lifeTime             根证书的有效期；
     * @param subject              根证书主题；
     * @return
     */
    CertificateAuthority createRootCertificateAuthority(String principal, CryptoKeypair key,
            int maxProgationDistance, long lifeTime, String subject);

    /**
     * 创建一个根 CA 实例；
     * 
     * @param principal            主体；
     * @param publicKey            背书证书的公钥；
     * @param privateKeySupplier   背书证书的私钥提供函数；
     * @param maxProgationDistance 根证书的最大传播距离；有效值要大于等于 0 ；
     *                             <p>
     *                             通过传播距离，可以控制证书链的延伸层级；
     *                             <p>
     *                             从根证书开始，每向下签发一级证书，新证书的最大传播距离至少减少 1 ，直至 0 ；
     *                             <p>
     *                             如果将根证书的最大传播距离设置为 0
     *                             时，意味着创建的根证书无法签发任何下级证书，根证书仅以自签名的方式自我认证；
     * @param lifeTime             根证书的有效期；
     * @param subject              根证书主题；
     * @return
     */
    CertificateAuthority createRootCertificateAuthority(String principal, PublicKey publicKey,
            Supplier<PrivateKey> privateKeySupplier,
            int maxProgationDistance, long lifeTime, String subject);

    /**
     * 创建一个 CA 实例；
     * 
     * @param cert 背书证书；即密钥对公钥得到的上级机构签发的证书，证书主体公钥与密钥对的公钥一致；
     * @param key  背书证书的密钥对；
     * 
     * @return
     */
    CertificateAuthority createCertificateAuthority(Certificate cert, CryptoKeypair key);

    /**
     * 创建一个 CA 实例；
     * 
     * @param cert               背书证书；即密钥对公钥得到的上级机构签发的证书，证书主体公钥与密钥对的公钥一致；
     * @param publicKey          背书证书的公钥；
     * @param privateKeySupplier 背书证书的私钥提供函数；
     * 
     * @return
     */
    CertificateAuthority createCertificateAuthority(Certificate cert, PublicKey publicKey,
            Supplier<PrivateKey> privateKeySupplier);

    /**
     * 验证指定证书链的有效性；
     * 
     * <p>
     * 验证不通过时抛出异常 {@link CertificateException} ；
     * 
     * @param cert 证书；
     * @return
     */
    void verify(Certificate cert) throws CertificateException;

    /**
     * 验证指定证书是否由指定的发行方公钥直接或间接签发；
     * 
     * <p>
     * 验证不通过时抛出异常 {@link CertificateException} ；
     * 
     * @param cert            证书；
     * @param issuerPublicKey 发行方公钥；
     * @return
     */
    void verifyIssuer(Certificate cert, PublicKey issuerPublicKey) throws CertificateException;

    /**
     * 验证指定证书链的有效性；
     * 
     * <p>
     * 验证通过时返回 true ；
     * <p>
     * 验证不通过时返回 false ；
     * 
     * @param cert 证书；
     * @return
     */
    boolean isValid(Certificate cert);

    /**
     * 验证指定证书是否由指定的发行方公钥直接或间接签发；
     * 
     * <p>
     * 验证通过时返回 true ；
     * <p>
     * 验证不通过时返回 false ；
     * 
     * @param cert            证书；
     * @param issuerPublicKey 发行方公钥；
     * @return
     */
    boolean isIssueBy(Certificate cert, PublicKey issuerPublicKey);

    /**
     * 将证书编码为字节数组；
     * 
     * @param certificate
     * @return
     */
    byte[] encode(Certificate certificate);

    /**
     * 解码为证书对象；
     * 
     * @param certificateBytes
     * @return
     */
    Certificate decode(byte[] certificateBytes);

}
